﻿using CSharpSkin.ComboBox.Class;
using CSharpSkin.ComboBox.Gdi;
using CSharpSkin.ComboBox.Struct;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
using System.ComponentModel;
namespace CSharpSkin.ComboBox
{
    #region 下拉框
    /// <summary>
    /// WWW.CSharpSkin.COM
    /// 下拉框
    /// </summary>
    public class CSharpComboBox:System.Windows.Forms.ComboBox
    {
        #region 下拉框句柄
        /// <summary>
        /// 下拉框句柄
        /// </summary>
        private IntPtr _comboxHandle;
        #endregion

        #region 下拉框状态
        /// <summary>
        /// 下拉框状态
        /// </summary>
        private ComboBoxState  _comboBoxState;
        #endregion

        #region 基础颜色
        private Color _baseColor = Color.Red;
        /// <summary>
        /// 基础颜色
        /// </summary>
        [Browsable(true)]
        [Description("下拉框基础颜色")]
        public Color BaseColor
        {
            get
            {
                return _baseColor;
            }
            set

            {
                _baseColor = value;
                this.Invalidate();
            }
        }
        #endregion

        #region 下拉框边框颜色
        private Color _borderColor = Color.Red;
        /// <summary>
        /// 下拉框边框颜色
        /// </summary>
        [Browsable(true)]
        [Description("下拉框边框颜色")]
        public Color BorderColor
        {
            get
            {
                return _borderColor;
            }
            set
            {
                _borderColor = value;
                this.Invalidate();
            }
        }
        #endregion

        #region 下拉框按钮箭头颜色
        private Color _arrowColor = Color.White;
        /// <summary>
        /// 下拉框按钮箭头颜色
        /// </summary>
        [Browsable(true)]
        [Description("下拉框按钮箭头颜色")]
        public Color ArrowColor
        {
            get
            {
                return _arrowColor;
            }
            set
            {
                _arrowColor = value;
                this.Invalidate();

            }
        }
        #endregion

        #region 是否重绘
        /// <summary>
        /// 是否重绘
        /// </summary>
        protected bool _isOpenPainting = true;
        #endregion

        #region 构造
        /// <summary>
        /// 构造
        /// </summary>
        public CSharpComboBox() : base()
        {
            //this.SetStyle(ControlStyles.UserPaint, true);
            this.SetStyle(ControlStyles.ResizeRedraw, true);
            this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
            this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
        }
        #endregion

        #region 返回下拉框按钮编辑区域
        /// <summary>
        /// 返回下拉框按钮编辑区域
        /// </summary>
        Rectangle ButtonRect
        {
            get
            {
                return GetDropDownButtonRect();
            }
        }
        #endregion

        #region 下拉框按钮是否按下
        /// <summary>
        /// 下拉框按钮是否按下
        /// </summary>
        bool IsComboBoxButtonPressed
        {
            get
            {
                if (IsHandleCreated)
                {
                    return GetComboBoxButtonPressed();
                }
                return false;
            }
        }
        #endregion

        #region 返回可绘制区域
        /// <summary>
        /// 返回可绘制区域
        /// </summary>
        Rectangle EditRect
        {
            get
            {
                if (DropDownStyle == ComboBoxStyle.DropDownList)
                {
                    Rectangle rect = new Rectangle(
                        3, 3, Width - ButtonRect.Width - 6, Height - 6);
                    if (RightToLeft == RightToLeft.Yes)
                    {
                        rect.X += ButtonRect.Right;
                    }
                    return rect;
                }
                if (IsHandleCreated && _comboxHandle != IntPtr.Zero)
                {
                    RECT rcClient = new RECT();
                    CSharpWinapi.GetWindowRect(_comboxHandle, ref rcClient);
                    return RectangleToClient(rcClient.Rect);
                }
                return Rectangle.Empty;
            }
        }
        #endregion

        #region 重写初始化控件事件，获取控件句柄
        /// <summary>
        /// 重写初始化控件事件，获取控件句柄
        /// </summary>
        protected override void OnCreateControl()
        {
            base.OnCreateControl();
            COMBOBOXINFO cbi = GetComboBoxInfo();
            _comboxHandle = cbi.hwndEdit;
        }
        #endregion

        #region 重写鼠标移动事件
        /// <summary>
        /// 重写鼠标移动事件
        /// </summary>
        /// <param name="e"></param>
        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);
            Point point = e.Location;
            if (ButtonRect.Contains(point))
            {
                _comboBoxState = ComboBoxState.Hover;
            }
            else
            {
                _comboBoxState = ComboBoxState.Normal;
            }
        }
        #endregion

        #region 重写鼠标进入事件
        /// <summary>
        /// 重写鼠标进入事件
        /// </summary>
        /// <param name="e"></param>
        protected override void OnMouseEnter(EventArgs e)
        {
            base.OnMouseEnter(e);

            Point point = PointToClient(Cursor.Position);
            if (ButtonRect.Contains(point))
            {
                _comboBoxState = ComboBoxState.Hover;
            }
        }
        #endregion

        #region 重写鼠标离开事件
        /// <summary>
        /// 重写鼠标离开事件
        /// </summary>
        /// <param name="e"></param>
        protected override void OnMouseLeave(EventArgs e)
        {
            base.OnMouseLeave(e);

            _comboBoxState = ComboBoxState.Normal;
        }
        #endregion

        #region 重写鼠标松下事件
        /// <summary>
        /// 重写鼠标松下事件
        /// </summary>
        /// <param name="e"></param>
        protected override void OnMouseUp(MouseEventArgs e)
        {
            base.OnMouseUp(e);
            _comboBoxState = ComboBoxState.Normal;
        }
        #endregion

        #region 监听系统消息，进行控件绘制
        /// <summary>
        /// 监听系统消息，进行控件绘制
        /// </summary>
        /// <param name="m"></param>
        protected override void WndProc(ref Message m)
        {
            switch (m.Msg)
            {
                case CSharpWinapi.WM_PAINT:
                    WMPaint(ref m);
                    break;
                default:
                    base.WndProc(ref m);
                    break;
            }
        }
        #endregion

        #region 根据系统消息进行绘制
        /// <summary>
        /// 根据系统消息进行绘制
        /// </summary>
        /// <param name="m"></param>
        private void WMPaint(ref Message m)
        {
            if (base.DropDownStyle == ComboBoxStyle.Simple)
            {
                base.WndProc(ref m);
                return;
            }
            if (base.DropDownStyle == ComboBoxStyle.DropDown)
            {
                if (_isOpenPainting)
                {
                    PAINTSTRUCT ps = new PAINTSTRUCT();
                    _isOpenPainting = false;
                    CSharpWinapi.BeginPaint(m.HWnd, ref ps);
                    RenderComboBox(ref m);
                    CSharpWinapi.EndPaint(m.HWnd, ref ps);
                    _isOpenPainting = true;
                    m.Result = WMRESULT.TRUE;
                }
                else
                {
                    base.WndProc(ref m);
                }
            }
            else
            {
                base.WndProc(ref m);
                RenderComboBox(ref m);
            }
        }
        #endregion

        #region 渲染下拉框
        /// <summary>
        /// 渲染下拉框
        /// </summary>
        /// <param name="m"></param>
        void RenderComboBox(ref Message m)
        {
            Rectangle rect = new Rectangle(Point.Empty, Size);
            Rectangle buttonRect = ButtonRect;
            ComboBoxState state = IsComboBoxButtonPressed ? ComboBoxState.Pressed : _comboBoxState;
            using (Graphics g = Graphics.FromHwnd(m.HWnd))
            {
                RenderComboBoxBackground(g, rect, buttonRect);
                RenderConboBoxDropDownButton(g, ButtonRect, state);
                RenderConboBoxBorder(g, rect);
            }
        }
        #endregion

        #region 渲染下拉框边框
        /// <summary>
        /// 渲染下拉框边框
        /// </summary>
        /// <param name="g"></param>
        /// <param name="rect"></param>
        void RenderConboBoxBorder(Graphics g, Rectangle rect)
        {
            Color borderColor = base.Enabled ?_borderColor : SystemColors.ControlDarkDark;
            using (Pen pen = new Pen(borderColor))
            {
                rect.Width--;
                rect.Height--;
                g.DrawRectangle(pen, rect);
            }
        }
        #endregion

        #region 渲染下拉框背景
        /// <summary>
        /// 渲染下拉框背景
        /// </summary>
        /// <param name="g"></param>
        /// <param name="rect"></param>
        /// <param name="buttonRect"></param>
        void RenderComboBoxBackground(Graphics g,Rectangle rect,Rectangle buttonRect)
        {
            Color backColor = base.Enabled ?base.BackColor : SystemColors.Control;
            using (SolidBrush brush = new SolidBrush(backColor))
            {
                buttonRect.Inflate(-1, -1);
                rect.Inflate(-1, -1);
                using (Region region = new Region(rect))
                {
                    region.Exclude(buttonRect);
                    region.Exclude(EditRect);
                    g.FillRegion(brush, region);
                }
            }
        }
        #endregion

        #region 渲染下拉框下拉按钮
        /// <summary>
        /// 渲染下拉框下拉按钮
        /// </summary>
        /// <param name="g"></param>
        /// <param name="buttonRect"></param>
        /// <param name="state"></param>
        void RenderConboBoxDropDownButton(Graphics g,Rectangle buttonRect,ComboBoxState state)
        {
            Color baseColor;
            Color backColor = Color.FromArgb(160, 250, 250, 250);
            Color borderColor = base.Enabled ?
                _borderColor : SystemColors.ControlDarkDark;
            Color arrowColor = base.Enabled ?
                _arrowColor : SystemColors.ControlDarkDark;
            Rectangle rect = buttonRect;

            if (base.Enabled)
            {
                switch (state)
                {
                    case ComboBoxState.Hover:
                        baseColor = ControlRender.GetColor(
                            _baseColor, 0, -33, -22, -13);
                        break;
                    case ComboBoxState.Pressed:
                        baseColor = ControlRender.GetColor(
                            _baseColor, 0, -65, -47, -25);
                        break;
                    default:
                        baseColor = _baseColor;
                        break;
                }
            }
            else
            {
                baseColor = SystemColors.ControlDark;
            }

            rect.Inflate(-1, -1);
            RenderComBoBoxScrollBarArrow(g,rect,baseColor,borderColor,backColor,arrowColor,RoundStyle.None,true,false,ArrowDirection.Down,LinearGradientMode.Vertical);
        }
        #endregion

        #region 绘制下拉框滚动条箭头
        /// <summary>
        /// 绘制下拉框滚动条箭头
        /// </summary>
        /// <param name="g"></param>
        /// <param name="rect"></param>
        /// <param name="baseColor"></param>
        /// <param name="borderColor"></param>
        /// <param name="innerBorderColor"></param>
        /// <param name="arrowColor"></param>
        /// <param name="roundStyle"></param>
        /// <param name="drawBorder"></param>
        /// <param name="drawGlass"></param>
        /// <param name="arrowDirection"></param>
        /// <param name="mode"></param>
        void RenderComBoBoxScrollBarArrow(Graphics g,Rectangle rect,Color baseColor,Color borderColor,Color innerBorderColor,Color arrowColor,RoundStyle roundStyle,bool drawBorder,bool drawGlass,ArrowDirection arrowDirection,LinearGradientMode mode)
        {
            ControlRender.RenderBackground(g,rect,baseColor,borderColor,innerBorderColor,roundStyle,0,0.45F,drawBorder,drawGlass, mode);
            using (SolidBrush brush = new SolidBrush(arrowColor))
            {
                RenderComBoBoxArrow(g,rect,arrowDirection,brush);
            }
        }
        #endregion

        #region 渲染下拉框箭头
        /// <summary>
        /// 渲染下拉框箭头
        /// </summary>
        /// <param name="g"></param>
        /// <param name="dropDownRect"></param>
        /// <param name="direction"></param>
        /// <param name="brush"></param>
        void RenderComBoBoxArrow(Graphics g, Rectangle dropDownRect,ArrowDirection direction,Brush brush)
        {
            Point point = new Point(dropDownRect.Left + (dropDownRect.Width / 2),dropDownRect.Top + (dropDownRect.Height / 2));
            Point[] points = null;
            switch (direction)
            {
                case ArrowDirection.Left:
                    points = new Point[] {
                        new Point(point.X + 2, point.Y - 3),
                        new Point(point.X + 2, point.Y + 3),
                        new Point(point.X - 1, point.Y) };
                    break;

                case ArrowDirection.Up:
                    points = new Point[] {
                        new Point(point.X - 3, point.Y + 2),
                        new Point(point.X + 3, point.Y + 2),
                        new Point(point.X, point.Y - 2) };
                    break;

                case ArrowDirection.Right:
                    points = new Point[] {
                        new Point(point.X - 2, point.Y - 3),
                        new Point(point.X - 2, point.Y + 3),
                        new Point(point.X + 1, point.Y) };
                    break;

                default:
                    points = new Point[] {
                        new Point(point.X - 2, point.Y - 1),
                        new Point(point.X + 3, point.Y - 1),
                        new Point(point.X, point.Y + 2) };
                    break;
            }
            g.FillPolygon(brush, points);
        }
        #endregion

        #region 返回系统下拉框
        /// <summary>
        /// 返回系统下拉框
        /// </summary>
        /// <returns></returns>
        private COMBOBOXINFO GetComboBoxInfo()
        {
            COMBOBOXINFO comBoBoxInfo = new COMBOBOXINFO();
            comBoBoxInfo.cbSize = Marshal.SizeOf(comBoBoxInfo);
            CSharpWinapi.GetComboBoxInfo(base.Handle, ref comBoBoxInfo);
            return comBoBoxInfo;
        }
        #endregion

        #region 获取下拉框按钮状态
        /// <summary>
        /// 获取下拉框按钮状态
        /// </summary>
        /// <returns></returns>
        private bool GetComboBoxButtonPressed()
        {
            COMBOBOXINFO comBoBoxInfo = GetComboBoxInfo();
            return comBoBoxInfo._comBoboxButtonState == COMBOBOXBUTTONSTATE.STATE_SYSTEM_PRESSED;
        }
        #endregion

        #region 获取下拉框按钮绘制区域
        /// <summary>
        /// 获取下拉框按钮绘制区域
        /// </summary>
        /// <returns></returns>
        private Rectangle GetDropDownButtonRect()
        {
            COMBOBOXINFO comBoBoxInfo = GetComboBoxInfo();
            return comBoBoxInfo.rcButton.Rect;
        }
        #endregion
    }
    #endregion
}
